/*
 * @Author: c
 * @Date: 2024-01-09 12:24:20
 * @LastEditTime: 2024-03-27 17:45:34
 * @LastEditors: c
 * @Description: 
 * @FilePath: \music-web-backend\src\core\music\album\album.service.ts
 * https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { plainToClass } from 'class-transformer';
import { EXCEPTION } from 'src/common/const/constants';
import { IOption } from 'src/common/dto/option.dto';
import { PageResDto } from 'src/common/dto/page.dto';
import { LangEnum } from 'src/common/enums';
import { CommonException } from 'src/common/exception/common.exception';
import { MinioClientService } from 'src/core/system/minio/minio.service';
import { User } from 'src/core/system/user/entities/user.entity';
import { DataSource, Repository } from 'typeorm';
import { Artist } from '../artist/entities/artist.entity';
import { Category } from '../category/entities/category.entity';
import { SongDto } from '../song/dto/search-song.dto';
import { Song } from '../song/entities/song.entity';
import { DAlbum } from './dao/album.dao';
import { AlbumForm, FavoriteForm, Pic } from './dto/create-album.dto';
import { AlbumDto, AlbumPageQuery } from './dto/search-album.dto';
import { Album } from './entities/album.entity';

@Injectable()
export class AlbumService {
  constructor(
    @InjectRepository(Album) private albumRepository: Repository<Album>,
    private dataSource: DataSource,
    private minioClientService: MinioClientService,
    private dalbum: DAlbum
  ) { }
  /**
  * 专辑-删除-我收藏的专辑
  * @param songForm 
  * @returns 
  */
  deletefavorite(user: User, songForm: FavoriteForm) {
    this.dalbum.deleteFavorite(user.id, songForm)
  }
  /**
   * 专辑-新增-我收藏的专辑
   * @param songForm 
   * @returns 
   */
  createfavorite(user: User, songForm: FavoriteForm) {
    this.dalbum.createFavorite(user.id, songForm)
  }

  /**
  * 专辑-我收藏的专辑
  * @param pageDto 
  * @returns 
  */
  async myfavorite(user: User, page: AlbumPageQuery) {
    const [data, total] = await this.dalbum.myfavorite(user?.id, page);
    let songVos: AlbumDto[] = await this.getList(user, data);
    return PageResDto.result(songVos, total)
  }


  getOne(albumId: number, username?: string): Promise<Album> {
    return this.dalbum.getOneByIdAndUsername(albumId, username)
  }

  /**
   * 专辑-根据id获取单条数据
   */
  async getOneById(id: number): Promise<AlbumDto> {

    const data = await this.dalbum.getOneById(id);

    let albumVo: AlbumDto = plainToClass(AlbumDto, data)
    albumVo.pic = plainToClass(Pic, data.pic)

    return albumVo
  }



  /**
   * 专辑-保存
   * @param albumForm 
   */
  async saveAlbum(albumForm: AlbumForm) {

    const album = plainToClass(Album, albumForm)
    const queryRunner = this.dataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();


    try {
      const res = await queryRunner.manager
        .createQueryBuilder()
        .insert()
        .into(Album)
        .values(album)
        .execute();
      const { id } = res.identifiers.at(0)
      await queryRunner.manager
        .createQueryBuilder()
        .relation(Album, 'pic')
        .of(id)
        .set(albumForm.pic.id);
      await queryRunner.manager
        .createQueryBuilder()
        .relation(Album, 'artistList')
        .of(id)
        .add(albumForm.artistIds);

      await queryRunner.manager
        .createQueryBuilder()
        .relation(Album, 'trackList')
        .of(id)
        .add(albumForm.songIds);

      await queryRunner.manager
        .createQueryBuilder()
        .relation(Album, 'genre')
        .of(id)
        .add(albumForm.genre);
      await queryRunner.commitTransaction();
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw new CommonException(EXCEPTION.COMMON);
    } finally {
      await queryRunner.release();
    }

  }

  /**
   * 专辑-修改
   * @param id 
   * @param updateAlbumDto 
   * @returns 
   */
  async update({ username }: User, id: number, albumForm: AlbumForm) {
    const { pic } = albumForm
    const oldAlbum = await this.getOne(id, username)
    const album = plainToClass(Album, albumForm)


    const artists = albumForm.artistIds.map(id => new Artist({ id }))
    const songs = albumForm.songIds.map(id => new Song({ id }))
    const cate = new Category(+albumForm.genre)

    //封面

    if (!oldAlbum.pic) {
      const pictureFile = await this.minioClientService.findOne(pic.id)
      album.pic = pictureFile
    } else if (oldAlbum.pic && oldAlbum.pic.id !== pic.id) {
      await this.minioClientService.deleteFileById(oldAlbum.pic.id)
      const pictureFile = await this.minioClientService.findOne(pic.id)
      album.pic = pictureFile
    }

    // const removeIds = oldAlbum.artistList.map(artist => artist.id);
    // await this.albumRepository
    //   .createQueryBuilder()
    //   .relation(Album, 'pic')
    //   .of(id)
    //   .addAndRemove(albumForm.artistIds)
    //类别
    album.genre = [cate]
    //歌手
    album.artistList = artists
    album.trackList = songs


    this.albumRepository.save(album)

  }

  /**
   * 专辑-删除
   * @param ids 
   */
  removeByIds(ids: number[]) {
    this.albumRepository.delete(ids)
  }

  /**
* 专辑-歌手所有专辑
* @param pageDto 
* @returns 
*/
  async getArtistAlbumList(user: User, page: AlbumPageQuery): Promise<PageResDto<Album>> {
    const [list, data] = await this.dalbum.getArtistAlbumList(user?.username, page)
    return PageResDto.result(list, data)
  }

  /**
   * 专辑-获取单个数据
   * @param req 
   * @param id 
   */
  async getAlbumFormData(user: User, id: number) {

    const data = await this.getOne(id, user?.username);
    if (data) {

      let albumVo: AlbumDto = plainToClass(AlbumDto, data)
      albumVo.pic = plainToClass(Pic, data.pic)

      let songVos: SongDto[] = []

      for await (const song of data.trackList) {

        let songVo: SongDto = plainToClass(SongDto, song);

        if (user?.username) {
          songVo.isFavorite = song.favoriteUsers.length > 0;
        }

        songVos.push(songVo)
      }

      albumVo.trackList = songVos
      return albumVo
    }
  }

  /**
   * 专辑-下拉列表查询
   * @param user 
   * @param pageDto 
   */
  async listOptions({ username }: User, { pageNum, pageSize, alubmName }: AlbumPageQuery) {
    const data = await this.dalbum.listOptions(pageNum, pageSize, alubmName);

    return data.map(({ id, title }) => {

      const option = new IOption<string, number>()
      option.value = id
      option.label = title
      return option
    })
  }

  /**
   * 专辑-分页查询
   * @param param0 
   * @param param1 
   * @returns 
   */
  async findAll(user: User, query: AlbumPageQuery) {

    const [data, total] = await this.dalbum.page(user?.username,query);

    let albumVos: AlbumDto[] = []

    for await (const album of data) {

      let albumVo: AlbumDto = plainToClass(AlbumDto, album);

      if (user?.username) {
        albumVo.isFavorite = album.favoriteUsers.length > 0;
        albumVo.isPaid = album.trackList.filter(song => song.paidUsers.length > 0 || song.payModel === 2).length > 0
      }
      albumVo.pic = plainToClass(Pic, album.pic)
      albumVo.lang = LangEnum.CN

      albumVos.push(albumVo)
    }

    return PageResDto.result(albumVos, total)
  }

  /**
   * 专辑-秀动发行
   * @param param0 
   * @param param1 
   */
  async xdpublish(user: User, { pageNum, pageSize }: AlbumPageQuery) {
    const [data, total] = await this.dalbum.xdpublish(user?.username, pageNum, pageSize);

    let albumVos: AlbumDto[] = []

    for await (const album of data) {

      let albumVo: AlbumDto = plainToClass(AlbumDto, album);

      albumVo.isFavorite = album.favoriteUsers ? album.favoriteUsers.length > 0 : false;
      albumVo.pic = plainToClass(Pic, album.pic)
      albumVo.lang = LangEnum.CN

      albumVos.push(albumVo)
    }

    return PageResDto.result(albumVos, total)
  }


  async getList(user: User, data: Album[]) {
    let albumVos: AlbumDto[] = []

    for await (const album of data) {

      let albumVo: AlbumDto = plainToClass(AlbumDto, album);

      if (user?.username) {
        albumVo.isFavorite = album.favoriteUsers.length > 0;
        albumVo.isPaid = album.trackList.filter(song => song.paidUsers.length > 0 || song.payModel === 2).length > 0
      }
      albumVo.pic = plainToClass(Pic, album.pic)
      albumVo.lang = LangEnum.CN

      albumVos.push(albumVo)
    }

    return albumVos
  }

}
